package com.wqr.it.ecwdr.service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;

import javax.transaction.Transactional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.wqr.it.ecwdr.dao.IProductDao;
import com.wqr.it.ecwdr.dto.ProductDto;
import com.wqr.it.ecwdr.dto.StockDto;
import com.wqr.it.ecwdr.dto.StockItemDto;
import com.wqr.it.ecwdr.util.DateUtils;
import com.wqr.it.ecwdr.vo.PageVO;
import com.wqr.it.ecwdr.vo.ProductItemVO;
import com.wqr.it.ecwdr.vo.ProductSalesInfoVO;
import com.wqr.it.ecwdr.vo.SallerVO;

@Async
@Service
@CacheConfig(cacheNames = "stock")
@Transactional
public class StockService {
	private static final Logger log = LoggerFactory.getLogger("INFO");
	private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
	@Value("${ecwdr.stock.productQueueSize}")
	private int stockProductQueueSize = 200;
	@Value("${ecwdr.user}")
	private String user;
	
	private ArrayBlockingQueue<ProductDto> productQueue = new ArrayBlockingQueue<>((int)(stockProductQueueSize * 1.2));

	@Autowired  
    private OptionService optionService;
	@Autowired  
    private SallerService sallerService;
	
	@Autowired
	private ProductService productService;

	@Autowired  
    private IProductDao productDao;

	private PageVO pageVO = new PageVO();
	
	private Random ran = new Random();
	
	@Cacheable(key="stock.fav.token")
	private int findFavStockToken() {
		return optionService.generateToken("stock.fav.token", false);
	}
	@CachePut(key="stock.fav.token")
	private int updateFavStockToken() {
		return optionService.generateToken("stock.fav.token", true);
	}
	
	public StockService() {
		pageVO.setCurPage(ran.nextInt(25) + 10);		
	}
	
	@Scheduled(fixedRate=2000) 
	public void schedule() {
		log.info("Start getFavSallerProductList");
		if (productQueue.size() > stockProductQueueSize) {
			log.info("getFavSallerProductList, queue is full");
			return;
		}
		pageVO.setPageSize(stockProductQueueSize);
		List<ProductItemVO> productItemList = null;
		long stockToken = findFavStockToken();
		productItemList = productDao.getFavSallerProductList(stockToken, pageVO);
		if (!CollectionUtils.isEmpty(productItemList)) {
			if (pageVO.getCurPage() > 35) {
				pageVO.setCurPage(1);
			} else {
				pageVO.setCurPage(pageVO.getCurPage() + 1);
			}
			ProductDto productDto = null;
			for (ProductItemVO productItemVO : productItemList) {
				productDto = new ProductDto();
				productDto.setId(productItemVO.getId());
				productDto.setNumber(productItemVO.getNumber());
				productDto.setCountryId(productItemVO.getCountryId());
				productDto.setSourceId(productItemVO.getSourceId());
				
				if (!productQueue.offer(productDto)) {
					break;
				}
			}
		} else {
			if (pageVO.getCurPage() == 1) {
				long newToken = Long.parseLong(sdf.format(new Date()));
				if (newToken > stockToken) {
					updateFavStockToken();
				}
			}
			pageVO.setCurPage(1);
		}
	}

	public List<ProductDto> findProductAll() {
		int pageSize = stockProductQueueSize / 2;
		if (pageSize < 20) {
			pageSize = 20;
		}
		List<ProductDto> list = new ArrayList<ProductDto>(pageSize);
		ProductDto productDto = null;
		
		for (int i = 0; i < pageSize; i++) {
			productDto = productQueue.poll();
			if (productDto == null) {
				break;
			} else {
				list.add(productDto);
			}			
		}
		if (productQueue.size() < pageSize) {
			schedule();
		}
		return list;
	}

	@Transactional
	public void save(StockDto stockDto) {
		String clientName = stockDto.getClientName();
		List<StockItemDto> list = stockDto.getItemList();
		ProductItemVO productItemVO = new ProductItemVO();
		productItemVO.setNumber(stockDto.getNumber());
		productItemVO.setCountryId(stockDto.getCountryId());
		productItemVO.setSourceId(stockDto.getSourceId());
		productItemVO.setCreatedBy(clientName);
		productItemVO.setLastUpdatedBy(clientName);
		long stockToken = findFavStockToken();
		long productId = productService.getProductId(productItemVO);
		
		productItemVO.setId(productId);
		productItemVO.setStockToken(stockToken);
		if (!CollectionUtils.isEmpty(list)) {
			productItemVO.setType(0);
			productItemVO.setFollow(list.size());
		} else {
			productItemVO.setType(1);
			productItemVO.setFollow(0);
		}
		productItemVO.setFollowToken(productService.findProductItemFollowToken());
		productService.updateProduct(productItemVO);
		if (productId <= 0) {
			productId = productItemVO.getId();
		}
		
		System.out.println(DateUtils.currentDate() + " Save " + productItemVO);
		
		ProductSalesInfoVO vo = null;		
		SallerVO sallerVO = null;
		ProductItemVO tmp = null;
		for (StockItemDto stockItemDto : list) {
			vo = new ProductSalesInfoVO();
			vo.setId(productId);
			vo.setNumber(productItemVO.getNumber());
			vo.setLastUpdatedBy(clientName);
			
			sallerVO = sallerService.findBySn(stockItemDto.getSallerSn(), stockDto.getCountryId(), stockDto.getSourceId());
			if (sallerVO == null) {
				sallerVO = new SallerVO();
				sallerVO.setSn(stockItemDto.getSallerSn().toLowerCase());
				sallerVO.setTitle(stockItemDto.getSallerSn());
				sallerVO.setCountryId(stockDto.getCountryId());
				sallerVO.setCountry(stockDto.getCountryId());
				sallerVO.setSourceId(stockDto.getSourceId());
				sallerVO.setSource(stockDto.getSourceId());
				sallerVO = sallerService.save(sallerVO);
			}
			vo.setSallerId(sallerVO.getId());
			vo.setStockToken(stockToken);
			vo.setPrice(stockItemDto.getPrice());
			vo.setStock(stockItemDto.getStock());
			vo.setSku(stockItemDto.getSku());
			vo.setItemId(stockItemDto.getItemId());
			
			tmp = productDao.getProductStock(vo);
			if (tmp == null) {
				vo.setCreatedBy(clientName);
				productDao.insertProductStock(vo);
			} else if (tmp.getStock() < 0) {
				vo.setStockId(tmp.getId());
				productDao.updateProductStock(vo);
			} else {
				System.out.println(DateUtils.currentDate() + " Skip " + vo);
			}
			// log.info(vo.toString());
		}
	}
	@Transactional
	public int refreshToken() {
		return updateFavStockToken();
	}

}
